

#ifndef _SYNC_H
#define _SYNC_H

#ifdef _WIN32
#  include <windows.h>
#else
#  include <pthread.h>

#  include <time.h>
#  include <sys/time.h>
#  ifdef __APPLE__
/** \brief MacOSX not supported unnamed sem_t
 *
 */
#    include "semaphore/semaphore_mach.h"
#  else
#    include <semaphore.h>
#  endif
#endif

class Semaphore {
public:
  Semaphore();
  ~Semaphore();

  int down(int timeout=-1);
  void up();

#ifdef _WIN32
  HANDLE sem;
#elif __APPLE__
  semaphore_t sem;
#else
  sem_t sem;
#endif
};


#ifdef _WIN32  // Win32 implementation

inline Semaphore::Semaphore()
{
  sem = CreateSemaphore(NULL, 0, 8192, NULL);
}

inline Semaphore::~Semaphore()
{
  if (sem)
    CloseHandle(sem);
}

inline int Semaphore::down(int timeout)
{
  return WaitForSingleObject(sem, timeout<0?INFINITE:timeout);
}

inline void Semaphore::up()
{
  ReleaseSemaphore(sem, 1, NULL);
}

#elif __APPLE__

inline Semaphore::Semaphore()
{
  sem_create_mach( &sem, 0 );
}

inline Semaphore::~Semaphore()
{
  sem_destrory_mach( &sem );
}

inline int Semaphore::down(int timeout)
{
  return sem_timedwait_mach( &sem, timeout );
}

inline void Semaphore::up()
{
  sem_signal_mach(&sem);
}

#else    // Linux implementation


inline Semaphore::Semaphore()
{
  sem_init(&sem, 0, 0);
}

inline Semaphore::~Semaphore()
{
  sem_destroy(&sem);
}

inline int Semaphore::down(int timeout)
{
  if(timeout<0)
    return sem_wait(&sem);
  else
  {
    struct timespec ts;
    struct timeval tt;  
        gettimeofday(&tt,NULL);
                u_int32_t timeout_sec = timeout / 1000;
                u_int32_t timeout_us = (timeout % 1000) * 1000;
                ts.tv_sec = tt.tv_sec + timeout_sec;
                ts.tv_nsec = tt.tv_usec * 1000 + timeout_us * 1000;
                ts.tv_sec += ts.tv_nsec / (1000 * 1000 *1000);
                ts.tv_nsec %= (1000 * 1000 * 1000);
                if (ts.tv_nsec >= 1000 * 1000 * 1000)
    {   
                        ts.tv_nsec -= 1000 * 1000 * 1000;
      ts.tv_sec++;   
    }
    return sem_timedwait(&sem, &ts);
  }
  
}

inline void Semaphore::up()
{
  sem_post(&sem);
}

#endif    // _WIN32

#endif
